#include "en.hpp"
#include "path.h"
#include <string.h>
#include <iostream>
#include "physics.hpp"

using namespace std;

void en::init()
{
    for(auto& i : peon::trait_list)
    {
        satisfying_peon_jobs.push_back({});
    }

    map_const_x = ceilf((float)en::w/c_map_x);
    map_const_y = ceilf((float)en::h/c_map_y);
}

void en::tick()
{

    if(t.getElapsedTime().asMilliseconds() < 16)
    {
        render = false;
        return;
    }

    t.restart();

    render = true;

    for(int i=0; i<w; i++)
    {
        memset(collision_win[i], NON_PATHABLE, h*sizeof(pathable));
    }

    sf::RectangleShape rect;

    for(auto& i : squares)
    {
        rect.setPosition(i.ax, i.ay);
        rect.setSize({i.bx - i.ax, i.by - i.ay});
        rect.setFillColor(i.col);

        for(int x=i.ax; x<i.bx; x++)
        {
            if(x >= 0 && x < en::w)
            {
                for(int y=i.ay; y<i.by; y++)
                {
                    if(y < 0 || y >= en::h)
                        continue;

                    collision_win[x][y] = i.is_pathable;
                }
            }
        }

        win.draw(rect);
    }

    for(auto& i : blocks)
    {
        int width, height;
        width = art_t[i->art_num].getSize().x;
        height = art_t[i->art_num].getSize().y;

        for(int x = i->x; x<i->x + width; x++)
        {
            if(x >= 0 && x < en::w)
            {
                for(int y = i->y; y<i->y + height; y++)
                {
                    if(y < 0 || y >= en::h)
                        continue;

                    collision_win[x][y] = NON_PATHABLE;

                    int px, py;
                    px = x / en::map_const_x;
                    py = y / en::map_const_y;

                    if(dens_prev!=NULL)
                    {
                        dens_prev[px + c_map_x*py] = 0.0f;
                        u_prev[px + c_map_x*py] = 0;
                        v_prev[px + c_map_x*py] = 0;
                    }

                }
            }
        }
    }

    //if(t.getElapsedTime().asMilliseconds() > 16)
    {
        for(auto& i : blocks)
        {
            i->tick();
        }

        assign_jobs();

        for(auto& i : peons)
        {
            //i->path(mouse.getPosition(en::win).x, mouse.getPosition(en::win).y);
            i->path();
            i->move(t.getElapsedTime().asMilliseconds());
            i->tick();
        }

        //t.restart();
    }

    for(auto& i : blocks)
    {
        sf::Sprite spr;
        spr.setTexture(en::art_t[i->art_num]);
        spr.setPosition(i->x, i->y);

        win.draw(spr);
    }

    for(auto& i : peons)
    {
        rect.setPosition(i->x - 1, i->y - 1);
        rect.setSize({3, 3});
        rect.setFillColor(i->col);

        win.draw(rect);
    }
}

void en::display()
{
    if(render)
    win.display();
}

void en::clear()
{
    if(render)
    win.clear();
}

void en::save()
{
    FILE* pFile = fopen("save.txt", "w+");
    for(auto& i : squares)
    {
        fprintf(pFile, "%i %i %i %i %i %i %i %i;", i.ax, i.ay, i.bx, i.by, i.col.r, i.col.g, i.col.b, i.is_pathable);
    }

    fprintf(pFile, "e\n");

    for(auto& i : peons)
    {
        fprintf(pFile, "%f %f %i %i %i;", i->x, i->y, i->col.r, i->col.g, i->col.b);
    }

    fprintf(pFile, "f\n");

    for(auto& i : blocks)
    {
        fprintf(pFile, "%i %i %i %i;", i->x, i->y, i->art_num, i->type_id);
    }

    fclose(pFile);
}

void en::load()
{
    FILE* pFile = fopen("save.txt", "r");

    squares.clear();
    peons.clear();

    int fsc = 0;

    do
    {
        square sq;
        fsc = fscanf(pFile, "%i %i %i %i %i %i %i %i;", &sq.ax, &sq.ay, &sq.bx, &sq.by, &sq.col.r, &sq.col.g, &sq.col.b, &sq.is_pathable);

        sq.col.a = 255;

        if(fsc>0)
            squares.push_back(sq);

    }
    while(fsc>0);

    fscanf(pFile, "e\n");

    do
    {
        peon pn;
        fsc = fscanf(pFile, "%f %f %i %i %i;", &pn.x, &pn.y, &pn.col.r, &pn.col.g, &pn.col.b);

        pn.col.a = 255;

        peon* pnp = new peon;
        *pnp = pn;

        if(fsc>0)
            peons.push_back(pnp);

    }
    while(fsc>0);

    fscanf(pFile, "f\n");

    do
    {
        block b;
        fsc = fscanf(pFile, "%i %i %i %i;", &b.x, &b.y, &b.art_num, &b.type_id);

        if(fsc > 0)
        {
            b.init(b.type_id);
            b.push();
        }
    }
    while(fsc>0);

    fclose(pFile);
}

void en::add_job(std::shared_ptr<job> j)
{
    jobs.push_back(j);
}

void en::load_traits()
{
    FILE* pFile = fopen("types.txt", "r");

    int fsc = 0;

    do
    {
        char name[100];
        memset(name, 0, 100);
        fsc = fscanf(pFile, "%s", name);

        fscanf(pFile, "\n");
        fscanf(pFile, "{\n");

        if(fsc == 0)
            break;

        std::vector<pair<string, float>> traits;

        int fsc2 = 1;

        while(fsc2 > 0)
        {
            float val = -1;
            fsc2 = fscanf(pFile, "%s %f\n", name, &val);

            pair<string, float> strfl = {string(name), val};

            traits.push_back(strfl);

            int n = 0;
            fscanf(pFile, "}%n", &n);
            if(n == 1)
            {
                break;
            }

            memset(name, 0, 100);
        }

        if(fsc > 0)
            en::trait_list.push_back(traits);

    }
    while(fsc>0);


    for(auto& i : en::trait_list)
    {
        cout << endl;
        for(auto& j : i)
        {
            cout << j.first << " " << j.second << endl;
        }
    }

    fclose(pFile);
}

bool en::contains_trait(int n, string& str, int* pos)
{
    int p = 0;
    for(auto& i : trait_list[n])
    {
        if(i.first == str)
        {
            if(pos!=0)
                *pos = p;

            return true;
        }
        p++;
    }

    return false;
}

bool en::contains_trait(vector<pair<string,float>>& v, string& str, int* pos)
{
    int p = 0;
    for(auto& i : v)
    {
        if(i.first == str)
        {
            if(pos!=0)
                *pos = p;

            return true;
        }
        p++;
    }

    return false;
}
bool en::contains_trait(vector<string>& v, string& str, int* pos)
{
    int p = 0;
    for(auto& i : v)
    {
        if(i == str)
        {
            if(pos!=0)
                *pos = p;

            return true;
        }
        p++;
    }

    return false;
}

float en::get_val(vector<pair<string,float>>& v, string& str)
{
    for(auto& i : v)
    {
        if(i.first == str)
        {
            return i.second;
        }
    }

    return -1;
}

int en::find_trait(vector<pair<string,float>>& v, string& str)
{
    int n = 0;
    for(auto& i : v)
    {
        if(i.first == str)
        {
            return n;
        }
        n++;
    }

    return -1;
}

std::vector<peon*> en::peons;
std::vector<square> en::squares;
std::vector<block*> en::blocks;

std::vector<std::shared_ptr<job>> en::jobs;
std::vector<std::vector<std::shared_ptr<job>>> en::satisfying_peon_jobs;

std::vector<sf::Texture> en::art_t;

std::vector<std::vector<std::pair<std::string, float>>> en::trait_list;

sf::RenderWindow en::win;

pathable** en::collision_win;

sf::Clock en::t;

unsigned int en::state = 0; ///pathfinding state still valid

int en::w = 1024;
int en::h = 768;

float en::map_const_x;
float en::map_const_y;

bool en::render = false;
